﻿//
// ParallelGrep
//
// Copyright (C) 2011 - Tatsuya Niioka
//
using System;
using System.Collections.ObjectModel;
using System.Windows.Input;
using System.IO;
using GrepEngine;
using System.Configuration;
using ParallelGrep.Configuration;
using ParallelGrep.Model;
using ParallelGrep.Properties;
using System.Globalization;

namespace ParallelGrep.ViewModel
{
    /// <summary>
    /// メインViewModelクラス
    /// </summary>
    public class MainViewModel : ViewModel
    {
        #region IsModified
        private bool m_isModified = false;
        /// <summary>
        /// 変更状態を取得または設定します。
        /// </summary>
        public bool IsModified
        {
            get { return m_isModified; }
            set { m_isModified = value; }
        }
        #endregion

        #region ReplaceViewModel
        private ReplaceViewModel m_replaceViewModel;
        /// <summary>
        /// 置換ViewModelを取得します。
        /// </summary>
        public ReplaceViewModel ReplaceViewModel
        {
            get {
                if (m_replaceViewModel == null)
                {
                    m_replaceViewModel = new ReplaceViewModel(this);
                }
                return m_replaceViewModel; 
            }
        }
        #endregion

        #region CharCodeConvertViewModel
        private CharCodeConvertViewModel m_charCodeConvertViewModel;
        /// <summary>
        /// 文字コード変換ViewModelを取得します。
        /// </summary>
        public CharCodeConvertViewModel CharCodeConvertViewModel
        {
            get {
                if (m_charCodeConvertViewModel == null)
                {
                    m_charCodeConvertViewModel = new CharCodeConvertViewModel(this);
                }
                return m_charCodeConvertViewModel; 
            }
        }
        #endregion

        #region IndentConvertViewModel
        private IndentConvertViewModel m_indentConvertViewModel;
        /// <summary>
        /// インデント変換ViewModelを取得します。
        /// </summary>
        public IndentConvertViewModel IndentConvertViewModel
        {
            get {
                if (m_indentConvertViewModel == null)
                {
                    m_indentConvertViewModel = new IndentConvertViewModel(this);
                }
                return m_indentConvertViewModel; 
            }
        }
        #endregion

        #region ProgressViewModel
        private ProgressViewModel m_progressViewModel;
        /// <summary>
        /// 進行状況ViewModelを取得します。
        /// </summary>
        public ProgressViewModel ProgressViewModel
        {
            get
            {
                if (m_progressViewModel == null)
                {
                    m_progressViewModel = new ProgressViewModel(this);
                }
                return m_progressViewModel;
            }
        }
        #endregion

        #region OperationViewModel
        private OperationViewModel m_oprationViewModel;
        /// <summary>
        /// オペレーションViewModelを取得します。
        /// </summary>
        public OperationViewModel OperationViewModel
        {
            get {
                if (m_oprationViewModel == null)
                {
                    m_oprationViewModel = new OperationViewModel(this);
                }
                return m_oprationViewModel; 
            }
        }
        #endregion

        #region Consts
        /// <summary>
        /// 大きいサイズのスケールを取得します。
        /// </summary>
        public const double BigSizeScale = 1.2;
        /// <summary>
        /// 普通サイズのスケールを取得します。
        /// </summary>
        public const double MiddleSizeScale = 1.0;
        /// <summary>
        /// 小さいサイズのスケールを取得します。
        /// </summary>
        public const double SmallSizeScale = 0.8;
        #endregion

        #region ScaleSize
        private double m_scaleSize = 1.0;
        /// <summary>
        /// スケールサイズを取得または設定します。
        /// </summary>
        public double ScaleSize
        {
            get { return m_scaleSize; }
            set
            {
                if (m_scaleSize == value)
                {
                    return;
                }
                m_scaleSize = value;
                foreach (MenuInfo<double> size in ScaleSizes)
                {
                    if (size.Value == ScaleSize)
                    {
                        size.IsChecked = true;
                    }
                    else
                    {
                        size.IsChecked = false;
                    }
                }
                OnPropertyChanged("ScaleSize");
            }
        }
        #endregion

        #region ScaleSizes
        private ObservableCollection<MenuInfo<double>> m_scaleSizes;
        /// <summary>
        /// スケールサイズメニュー一覧を取得します。
        /// </summary>
        public ObservableCollection<MenuInfo<double>> ScaleSizes
        {
            get
            {
                if (m_scaleSizes == null)
                {
                    m_scaleSizes = new ObservableCollection<MenuInfo<double>>();
                }
                return m_scaleSizes;
            }
        }
        #endregion

        //#region Theme
        //private string m_theme;
        ///// <summary>
        ///// テーマ名を取得または設定します。
        ///// </summary>
        //public string Theme
        //{
        //    get { return m_theme; }
        //    set
        //    {
        //        if (m_theme == defaultValue)
        //        {
        //            return;
        //        }
        //        m_theme = defaultValue;
        //        OnPropertyChanged("ThemeName");
        //    }
        //}
        //#endregion

        //#region Themes
        //private ObservableCollection<string> m_themeNames;
        ///// <summary>
        ///// テーマ一覧を取得します。
        ///// </summary>
        //public ObservableCollection<string> Themes
        //{
        //    get
        //    {
        //        if (m_themeNames == null)
        //        {
        //            m_themeNames = new ObservableCollection<string>();
        //        }
        //        return m_themeNames;
        //    }
        //}
        //#endregion



        #region size
        private GrepInfo m_info = null;
        /// <summary>
        /// Grepエンティティを取得または設定します。
        /// </summary>
        internal GrepInfo Info
        {
            get
            {
                if (m_info == null)
                {
                    m_info = new GrepInfo();
                }
                return m_info;
            }
            set
            {
                m_info = value;
            }
        }
        #endregion

        #region IsEnabled
        /// <summary>
        /// 有効状態を取得します。
        /// </summary>
        public bool IsEnabled
        {
            get
            {
                return !IsRunner;
            }
        }
        #endregion

        #region IsRunner
        private bool m_isRunner = false;
        /// <summary>
        /// 実行状態を取得または設定します。
        /// </summary>
        public bool IsRunner
        {
            get
            {
                return m_isRunner;
            }
            internal set
            {
                if (m_isRunner == value)
                {
                    return;
                }
                m_isRunner = value;
                OnPropertyChanged("IsRunner");
                OnPropertyChanged("IsEnabled");
            }
        }
        #endregion
 
        #region Description
        /// <summary>
        /// 概要を取得または設定します。
        /// </summary>
        public string Description
        {
            get
            {
                return Info.Description;
            }
            set
            {
                if (Info.Description == value)
                {
                    return;
                }
                Info.Description = value;
                OnPropertyChanged("Description");
                IsModified = true;
            }
        }
        #endregion

        #region Value
        /// <summary>
        /// パスを取得または設定します。
        /// </summary>
        public string Path
        {
            get
            {
                return Info.Path;
            }
            set
            {
                if (Info.Path == value)
                {
                    return;
                }
                if (Paths.Contains(value))
                {
                    Paths.Remove(value);
                }
                Paths.Insert(0, value);
                Info.Path = value;
                OnPropertyChanged("Path");
                IsModified = true;
            }
        }
        #endregion

        #region SearchPattern
        /// <summary>
        /// 検索パターンを取得または設定します。
        /// </summary>
        public string SearchPattern
        {
            get
            {
                return Info.SearchPattern;
            }
            set
            {
                if (Info.SearchPattern == value)
                {
                    return;
                }
                if (SearchPatterns.Contains(value))
                {
                    SearchPatterns.Remove(value);
                }
                SearchPatterns.Insert(0, value);
                Info.SearchPattern = value;
                OnPropertyChanged("SearchPattern");
                IsModified = true;
            }
        }
        #endregion

        #region InputEncodingName
        /// <summary>
        /// 入力エンコーディング名を取得または設定します。
        /// </summary>
        public string InputEncodingName
        {
            get { 
                return Info.InputEncodingName.ToString();
            }
            set
            {
                InputEncodingMode encoding;
                try
                {
                    encoding = (InputEncodingMode)Enum.Parse(typeof(InputEncodingMode), value);
                }
                catch
                {
                    return;
                }
                if (Info.InputEncodingName == encoding)
                {
                    return;
                }
                Info.InputEncodingName = encoding;
                OnPropertyChanged("InputEncodingName");
                IsModified = true;
            }
        }
        #endregion

        #region SearchOption
        /// <summary>
        /// 検索オプションを取得または設定します。
        /// </summary>
        public SearchOption SearchOption
        {
            get
            {
                return Info.SearchOption;
            }
            set
            {
                Info.SearchOption = value;
            }
        }
        #endregion

        #region IsAllDirectories
        /// <summary>
        /// 検索オプションを取得または設定します。
        /// </summary>
        public bool IsAllDirectories
        {
            get
            {
                return SearchOption == SearchOption.AllDirectories;
            }
            set
            {
                SearchOption op = SearchOption.AllDirectories;
                if (value)
                {
                    op = SearchOption.AllDirectories;
                }
                else
                {
                    op = SearchOption.TopDirectoryOnly;
                }
                if (SearchOption == op)
                {
                    return;
                }
                SearchOption = op;
                OnPropertyChanged("IsAllDirectories");
                IsModified = true;
            }
        }
        #endregion

        #region SearchValue
        /// <summary>
        /// 検索文字列を取得または設定します。
        /// </summary>
        public string SearchValue
        {
            get
            {
                return Info.SearchValue;
            }
            set
            {
                if (Info.SearchValue == value)
                {
                    return;
                }
                if (SearchValues.Contains(value))
                {
                    SearchValues.Remove(value);
                }
                SearchValues.Insert(0, value);
                Info.SearchValue = value;
                OnPropertyChanged("SearchValue");
                IsModified = true;
            }
        }
        #endregion

        #region Process
        /// <summary>
        /// 処理モードを取得または設定します。
        /// </summary>
        public string Process
        {
            get
            {
                return Info.Mode.ToString();
            }
            set
            {
                GrepMode mode;
                try
                {
                    mode = (GrepMode)Enum.Parse(typeof(GrepMode), value);
                }
                catch
                {
                    return;
                }
                if (Info.Mode == mode)
                {
                    return;
                }
                Info.Mode = mode;
                OnPropertyChanged("Process");
                IsModified = true;
            }
        }
        #endregion

        #region IsIgnoreCase
        /// <summary>
        /// 大文字小文字区別を取得または設定します。
        /// </summary>
        public bool IsIgnoreCase
        {
            get
            {
                return Info.IsIgnoreCase;
            }
            set
            {
                if (Info.IsIgnoreCase == value)
                {
                    return;
                }
                Info.IsIgnoreCase = value;
                OnPropertyChanged("IsIgnoreCase");
                IsModified = true;
            }
        }
        #endregion

        #region IsWord
        /// <summary>
        /// ワードを取得または設定します。
        /// </summary>
        public bool IsWord
        {
            get
            {
                return Info.IsWord;
            }
            set
            {
                if (Info.IsWord == value)
                {
                    return;
                }
                Info.IsWord = value;
                OnPropertyChanged("IsWord");
                IsModified = true;
            }
        }
        #endregion

        #region IsConditions
        /// <summary>
        /// 検索条件状態を取得または設定します。
        /// </summary>
        public bool IsConditions
        {
            get
            {
                return Info.IsConditions;
            }
            set
            {
                if (Info.IsConditions == value)
                {
                    return;
                }
                Info.IsConditions = value;
                OnPropertyChanged("IsConditions");
                IsModified = true;
            }
        }
        #endregion

        #region ConditionsMode
        /// <summary>
        /// 検索条件を取得または設定します。
        /// </summary>
        public string ConditionsMode
        {
            get
            {
                return Info.ConditionsMode.ToString();
            }
            set
            {
                ConditionsMode mode;
                try
                {
                    mode = (ConditionsMode)Enum.Parse(typeof(ConditionsMode), value);
                }
                catch
                {
                    return;
                }
                if (Info.ConditionsMode == mode)
                {
                    return;
                }
                Info.ConditionsMode = mode;
                OnPropertyChanged("ConditionsMode");
                IsModified = true;
            }
        }
        #endregion

        #region IsRepeart
        /// <summary>
        /// 反復処理状態を取得または設定します。
        /// </summary>
        public bool IsRepeart
        {
            get
            {
                return Info.IsRepeart;
            }
            set
            {
                if (Info.IsRepeart == value)
                {
                    return;
                }
                Info.IsRepeart = value;
                OnPropertyChanged("IsRepeart");
                IsModified = true;
            }
        }
        #endregion

        #region IsOutputPath
        /// <summary>
        /// 出力変更状態を取得または設定します。
        /// </summary>
        public bool IsOutputPath
        {
            get
            {
                return Info.IsOutputPath;
            }
            set
            {
                if (Info.IsOutputPath == value)
                {
                    return;
                }
                Info.IsOutputPath = value;
                OnPropertyChanged("IsOutputPath");
                IsModified = true;
            }
        }
        #endregion

        #region OutputPath
        /// <summary>
        /// 出力フォルダを取得または設定します。
        /// </summary>
        public string OutputPath
        {
            get
            {
                return Info.OutputPath;
            }
            set
            {
                if (Info.OutputPath == value)
                {
                    return;
                }
                if (OutputPaths.Contains(value))
                {
                    OutputPaths.Remove(value);
                }
                OutputPaths.Insert(0, value);
                Info.OutputPath = value;
                this.OnPropertyChanged("OutputPath");
                this.IsModified = true;
            }
        }
        #endregion

        #region StatusBarText
        private string m_statusBarText;
        /// <summary>
        /// ステータスバーテキストを取得または設定します。
        /// </summary>
        public string StatusBarText
        {
            get
            {
                return m_statusBarText;
            }
            set
            {
                if (m_statusBarText == value)
                {
                    return;
                }
                m_statusBarText = value;
                OnPropertyChanged("StatusBarText");
            }
        }
        #endregion

        #region IsOpen
        /// <summary>
        /// ファイルを開いた状態を取得します。
        /// </summary>
        public bool IsOpen
        {
            get
            {
                if (CurrentFileName != null)
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
        }
        #endregion

        #region CurrentFileName
        private string m_currentFileName = null;
        /// <summary>
        /// 現在のファイル名を取得または設定します。
        /// </summary>
        public string CurrentFileName
        {
            get { return m_currentFileName; }
            set {
                if (m_currentFileName == value)
                {
                    return;
                }
                m_currentFileName = value;
                OnPropertyChanged("CurrentFileName");
                OnPropertyChanged("IsOpen");
            }
        }
        #endregion

        #region FileOpenCommand
        private RelayCommand m_fileOpenCommand;
        /// <summary>
        /// ファイルを開くコマンドを取得します。
        /// </summary>
        public ICommand FileOpenCommand
        {
            get
            {
                if (m_fileOpenCommand == null)
                {
                    m_fileOpenCommand = new RelayCommand(param => this.FileOpen());
                }
                return m_fileOpenCommand;
            }
        }
        #endregion

        #region FileOpen
        /// <summary>
        /// ファイルを開くを実行します。
        /// </summary>
        public void FileOpen()
        {
            var dialog = new System.Windows.Forms.OpenFileDialog();
            dialog.Filter = Resources.GrepFileFilter;
            if (dialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                FileOpen(dialog.FileName);
            }
        }
        #endregion

        #region FileOpen
        /// <summary>
        /// 指定したファイル名を開きます。
        /// </summary>
        /// <param name="fileName">ファイル名</param>
        public void FileOpen(string fileName)
        {
            if (fileName == null)
            {
                throw new ArgumentNullException("fileName");
            }
            if (string.IsNullOrEmpty(fileName))
            {
                throw new ArgumentException("fileName");
            }
            if (!File.Exists(fileName))
            {
                throw new FileNotFoundException("ファイルが見つかりません。");
            }
            CurrentFileName = fileName;

            GrepInfo info = GrepFile.Load(fileName);
            Process = info.Mode.ToString();
            Description = info.Description;
            Path = info.Path;
            SearchValue = info.SearchValue;
            SearchPattern = info.SearchPattern;
            InputEncodingName = info.InputEncodingName.ToString();

            IsRepeart = info.IsRepeart;
            SearchOption = info.SearchOption;
            IsWord = info.IsWord;
            IsIgnoreCase = info.IsIgnoreCase;
            IsConditions = info.IsConditions;
            ConditionsMode = info.ConditionsMode.ToString();

            IndentConvertViewModel.IndentConvertMode = info.IndentConvertMode.ToString();
            IndentConvertViewModel.TabSize = info.TabSize;
            CharCodeConvertViewModel.OutputEncodingName = info.OutputEncodingName.ToString();
            CharCodeConvertViewModel.OutputLineEnd = info.OutputLineEnd.ToString();
           
            IsOutputPath = info.IsOutputPath;
            OutputPath = info.OutputPath;
            if (!string.IsNullOrWhiteSpace(Info.Description))
            {
                IsDescriptionVisible = true;
            }
            if (Info.IsOutputPath)
            {
                IsOutputVisible = true;
            }
            AllPropertyChanged();
            
            if (RecentFiles.Contains(CurrentFileName))
            {
                RecentFiles.Remove(CurrentFileName);
            }
            RecentFiles.Insert(0, CurrentFileName);
            while (RecentFiles.Count > 10)
            {
                RecentFiles.RemoveAt(10);
            }
        }
        #endregion

        #region ViewSizeChangedCommand
        private RelayCommand m_viewSizeChangedCommand;
        /// <summary>
        /// 表示サイズ変更コマンドを取得します。
        /// </summary>
        public ICommand ViewSizeChangedCommand
        {
            get
            {
                if (m_viewSizeChangedCommand == null)
                {
                    m_viewSizeChangedCommand = new RelayCommand(param => this.ViewSizeChanged(param));
                }
                return m_viewSizeChangedCommand;
            }
        }
        #endregion

        #region ViewSizeChanged
        /// <summary>
        /// 表示サイズを変更します。
        /// </summary>
        /// <param name="parameter">パラメータ</param>
        public void ViewSizeChanged(object parameter)
        {
            ScaleSize = (double)parameter;
        }
        #endregion

        #region CultureChangedCommand
        private RelayCommand m_cultureChangedCommand;
        /// <summary>
        /// カルチャ変更コマンドを取得します。
        /// </summary>
        public ICommand CultureChangedCommand
        {
            get
            {
                if (m_cultureChangedCommand == null)
                {
                    m_cultureChangedCommand = new RelayCommand(param => this.CultureChanged(param));
                }
                return m_cultureChangedCommand;
            }
        }
        #endregion

        #region CultureChanged
        /// <summary>
        /// カルチャ変更を実行します。
        /// </summary>
        /// <param name="parameter">パラメータ</param>
        public void CultureChanged(object parameter)
        {
            CultureInfo selectCulture = parameter as CultureInfo;
            foreach (MenuInfo<CultureInfo> culture in Cultures)
            {
                if (culture.Value.Name == selectCulture.Name)
                {
                    Culture = culture.Value;
                    break;
                }
            }
        }
        #endregion

        #region RecentFileOpenCommand
        private RelayCommand m_recentFileOpenCommand;
        /// <summary>
        /// 最近使ったファイルを開くコマンドを取得します。
        /// </summary>
        public ICommand RecentFileOpenCommand
        {
            get
            {
                if (m_recentFileOpenCommand == null)
                {
                    m_recentFileOpenCommand = new RelayCommand(param => this.RecentFileOpen(param));
                }
                return m_recentFileOpenCommand;
            }
        }
        #endregion

        #region RecentFileOpen
        /// <summary>
        /// 最近使ったファイルを開くを実行します。
        /// </summary>
        /// <param name="parameter"></param>
        public void RecentFileOpen(object parameter)
        {
            string fileName = parameter as string;
            if (CurrentFileName !=null)
            {
                // Sure ?
            }
            FileOpen(fileName);
        }
        #endregion

        #region AllPropertyChanged
        /// <summary>
        /// すべてのプロパティの変更通知します。
        /// </summary>
        internal void AllPropertyChanged()
        {
            OnPropertyChanged("Description");
            OnPropertyChanged("Path");
            OnPropertyChanged("SearchValue");
            OnPropertyChanged("SearchPattern");
            OnPropertyChanged("InputEncodingName");
            OnPropertyChanged("IsOutputPath");
            OnPropertyChanged("OutputPath");
            OnPropertyChanged("IsAllDirectories");
            OnPropertyChanged("Process");
            OnPropertyChanged("IsIgnoreCase");
            OnPropertyChanged("IsWord");
            OnPropertyChanged("IsConditions");
            OnPropertyChanged("ConditionsMode");
            OnPropertyChanged("IsRepeart");

            ReplaceViewModel.AllPropertyChanged();
            IndentConvertViewModel.AllPropertyChanged();
            CharCodeConvertViewModel.AllPropertyChanged();
            ProgressViewModel.AllPropertyChanged();
        }
        #endregion

        #region FileSaveCommand
        private RelayCommand m_fileSaveCommand;
        /// <summary>
        /// ファイルに保管コマンドを取得します。
        /// </summary>
        public ICommand FileSaveCommand
        {
            get
            {
                if (m_fileSaveCommand == null)
                {
                    m_fileSaveCommand = new RelayCommand(param => this.Save());
                }
                return m_fileSaveCommand;
            }
        }
        #endregion
        
        #region Save
        /// <summary>
        /// 保管をします。
        /// </summary>
        public void Save()
        {
            var dialog = new System.Windows.Forms.SaveFileDialog();
            dialog.Filter = Resources.GrepFileFilter;
            if (dialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                FileSave(dialog.FileName);
            }
        }
        #endregion

        #region FileSaveOverWriteCommand
        private RelayCommand m_fileSaveOverWriteCommand;
        /// <summary>
        /// ファイルに上書き保管コマンドを取得します。
        /// </summary>
        public ICommand FileSaveOverWriteCommand
        {
            get
            {
                if (m_fileSaveOverWriteCommand == null)
                {
                    m_fileSaveOverWriteCommand = new RelayCommand(param => this.SaveAsOverWrite());
                }
                return m_fileSaveOverWriteCommand;
            }
        }
        #endregion

        #region SaveAsOverWrite
        /// <summary>
        /// 上書き保存します。
        /// </summary>
        public void SaveAsOverWrite()
        {
            FileSave(CurrentFileName);
        }
        #endregion

        #region FileSave
        /// <summary>
        /// 指定したファイル名で保存します。
        /// </summary>
        /// <param name="fileName">ファイル名</param>
        public void FileSave(string fileName)
        {
            if (fileName == null)
            {
                throw new ArgumentNullException("fileName");
            }
            if (string.IsNullOrEmpty(fileName))
            {
                throw new ArgumentException("fileName");
            }
            if (File.Exists(fileName))
            {
                // sure ? override
            }
            GrepFile.Save(Info, fileName);
            if (RecentFiles.Contains(fileName))
            {
                RecentFiles.Remove(fileName);
            }
            RecentFiles.Insert(0, fileName);
            while (RecentFiles.Count > 10)
            {
                RecentFiles.RemoveAt(10);
            }
        }
        #endregion

        #region PathRefCommand
        private RelayCommand m_pathRefCommand;
        /// <summary>
        /// 検索フォルダ参照コマンドを取得します。
        /// </summary>
        public RelayCommand PathRefCommand
        {
            get {
                if (m_pathRefCommand == null)
                {
                    m_pathRefCommand = new RelayCommand(param => this.PathRef());
                }
                return m_pathRefCommand; 
            }
        }
        #endregion

        #region PathRef
        /// <summary>
        /// 検索フォルダを参照します。
        /// </summary>
        public void PathRef()
        {
            var dialog = new System.Windows.Forms.FolderBrowserDialog();
            if (dialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                Path = dialog.SelectedPath;
                if (!Paths.Contains(Path))
                {
                    Paths.Insert(0, Path);
                }
            }
        }
        #endregion

        #region OutputPathRefCommand
        private RelayCommand m_outputPathRefCommand;
        /// <summary>
        /// 出力フォルダ参照コマンドを取得します。
        /// </summary>
        public RelayCommand OutputPathRefCommand
        {
            get {
                if (m_outputPathRefCommand == null)
                {
                    m_outputPathRefCommand = new RelayCommand(param => this.OutputPathRef());
                }
                return m_outputPathRefCommand; 
            }
        }
        #endregion
        
        #region OutputPathRef
        /// <summary>
        /// 出力フォルダを選択します。
        /// </summary>
        public void OutputPathRef()
        {
            var dialog = new System.Windows.Forms.FolderBrowserDialog();
            if (dialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                OutputPath = dialog.SelectedPath;
                if (!OutputPaths.Contains(OutputPath))
                {
                    OutputPaths.Insert(0, OutputPath);
                }
            }
        }
        #endregion

        #region LocalizedStrings
        private LocalizedStrings m_localizedStrings = null;
        /// <summary>
        /// ローカライズ文字列を取得します。
        /// </summary>
        public LocalizedStrings LocalizedStrings
        {
            get
            {
                if (m_localizedStrings == null)
                {
                    if (App.Current != null)
                    {
                        m_localizedStrings = (LocalizedStrings)App.Current.Resources["LocalizedStrings"];
                    }
                    else
                    {
                        m_localizedStrings = new LocalizedStrings();
                    }
                }
                return m_localizedStrings;
            }
        }
        #endregion

        #region Culture
        private CultureInfo m_culture;
        /// <summary>
        /// 言語を取得または設定します。
        /// </summary>
        public CultureInfo Culture
        {
            get
            {
                if (m_culture == null)
                {
                    m_culture = new CultureInfo("ja-JP");
                }
                return m_culture;
            }
            set
            {
                if (LocalizedStrings.Culture != null &&
                    LocalizedStrings.Culture.Name == value.Name)
                {
                    return;
                }
                m_culture = value;
                LocalizedStrings.Culture = value;
                foreach (MenuInfo<CultureInfo> info in Cultures)
                {
                    if (info.Value.Name == value.Name)
                    {
                        info.IsChecked = true;
                    }
                    else
                    {
                        info.IsChecked = false;
                    }
                }
                ReLoadResources();
                OnPropertyChanged("Culture");
            }
        }
        #endregion

        #region ReLoadResources
        /// <summary>
        /// リソース再読み込みを実行します。
        /// </summary>
        public void ReLoadResources()
        {
            LoadResources();
            CharCodeConvertViewModel.LoadResources();
            IndentConvertViewModel.LoadResources();
            ProgressViewModel.LoadResources();
        }
        #endregion

        #region Cultures
        private ObservableCollection<MenuInfo<CultureInfo>> m_cultures;
        /// <summary>
        /// カルチャ一覧を取得します。
        /// </summary>
        public ObservableCollection<MenuInfo<CultureInfo>> Cultures
        {
            get
            {
                if (m_cultures == null)
                {
                    m_cultures = new ObservableCollection<MenuInfo<CultureInfo>>();
                }
                return m_cultures;
            }
        }
        #endregion

        #region ConfigLoad
        /// <summary>
        /// 履歴を読み込みします。
        /// </summary>
        public ConfigHandler ConfigLoad()
        {
            System.Configuration.Configuration configuration = (System.Configuration.Configuration)ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);

            ConfigHandler config = (ConfigHandler)configuration.GetSection("settings");
            if (config != null)
            {
                string[] cultures = config.Cultures.Split(new char[] { ';' });
                CultureInfo currentCulture = null;

                Cultures.Clear();
                foreach (string culture in cultures)
                {
                    CultureInfo info = new CultureInfo(culture);
                    Cultures.Add(new MenuInfo<CultureInfo>(info.NativeName, info, null));

                    if (culture == config.Culture)
                    {
                        currentCulture = info;
                    }
                }
                if (currentCulture == null)
                {
                    Culture = Cultures[0].Value;
                }
                else
                {
                    Culture = currentCulture;
                }
                ScaleSize= config.ScaleSize;
                IsDescriptionVisible= config.IsDescriptionVisible;
                IsOutputVisible = config.IsOutputVisible;

                if (config.ScaleSize != BigSizeScale &&
                    config.ScaleSize != MiddleSizeScale &&
                    config.ScaleSize != SmallSizeScale)
                {
                    ScaleSize = MiddleSizeScale;
                }

                foreach (ConfigElement path in config.Paths)
                {
                    Paths.Add(path.Text);
                }
                foreach (ConfigElement searchValue in config.SearchValues)
                {
                    SearchValues.Add(searchValue.Text);
                }
                foreach (ConfigElement searchPattern in config.SearchPatterns)
                {
                    SearchPatterns.Add(searchPattern.Text);
                }
                foreach (ConfigElement replacementValue in config.ReplacementValues)
                {
                    ReplaceViewModel.ReplacementValues.Add(replacementValue.Text);
                }
                foreach (ConfigElement recentFile in config.RecentFiles)
                {
                    RecentFiles.Add(recentFile.Text);
                }
            }
            return config;
        }
        #endregion

        #region ConfigSave
        /// <summary>
        /// 履歴を保管します。
        /// </summary>
        public void ConfigSave()
        {
            System.Configuration.Configuration configuration = (System.Configuration.Configuration)ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);

            ConfigHandler config = (ConfigHandler)configuration.GetSection("settings");
            if (config == null)
            {
                config = new ConfigHandler();
            }
            config.Culture = Culture.Name;
            config.ScaleSize = ScaleSize;
            config.IsDescriptionVisible = IsDescriptionVisible;
            config.IsOutputVisible = IsOutputVisible;

            config.Paths.Clear();
            config.SearchValues.Clear();
            config.SearchPatterns.Clear();
            config.ReplacementValues.Clear();
            config.RecentFiles.Clear();

            int idx = 0;
            foreach (string path in Paths)
            {
                idx++;
                ConfigElement element = new ConfigElement() { Name = idx.ToString(), Text = path };
                config.Paths.Add(element);
            }
            idx = 0;
            foreach (string searchValue in SearchValues)
            {
                idx++;
                ConfigElement element = new ConfigElement() { Name = idx.ToString(), Text = searchValue };
                config.SearchValues.Add(element);
            }
            idx = 0;
            foreach (string searchPattern in SearchPatterns)
            {
                idx++;
                ConfigElement element = new ConfigElement() { Name = idx.ToString(), Text = searchPattern };
                config.SearchPatterns.Add(element);
            }
            idx = 0;
            foreach (string replacementValue in ReplaceViewModel.ReplacementValues)
            {
                idx++;
                ConfigElement element = new ConfigElement() { Name = idx.ToString(), Text = replacementValue };
                config.ReplacementValues.Add(element);
            }
            idx = 0;
            foreach (string recentFile in RecentFiles)
            {
                idx++;
                ConfigElement element = new ConfigElement() { Name = idx.ToString(), Text = recentFile };
                config.RecentFiles.Add(element);
            }
            configuration.Save();
        }
        #endregion

        #region FileDropCommand
        private RelayCommand m_fileDropCommand;
        /// <summary>
        /// ファイルを開くコマンドを取得します。
        /// </summary>
        public ICommand FileDropCommand
        {
            get
            {
                if (m_fileDropCommand == null)
                {
                    m_fileDropCommand = new RelayCommand(param => this.FileDrop(param));
                }
                return m_fileDropCommand;
            }
        }
        /// <summary>
        /// ドラックを実行します。
        /// </summary>
        public void FileDrop(object parameter)
        {
            string[] files = (string[])parameter;
            if (files.Length > 0)
            {
                FileOpen(files[0]);
            }
        }
        #endregion

        //private string m_dropFile;
        ///// <summary>
        ///// ドロップファイルを取得または設定します。
        ///// </summary>
        //public string DropFile
        //{
        //    get
        //    {
        //        return m_dropFile;
        //    }
        //    set
        //    {
        //        m_dropFile = value;
        //        OnPropertyChanged("DropFile");
        //    }
        //}

        #region ExitCommand
        private RelayCommand m_exitCommand;
        /// <summary>
        /// エディタ起動コマンドを取得します。
        /// </summary>
        public ICommand ExitCommand
        {
            get
            {
                if (m_exitCommand == null)
                {
                    m_exitCommand = new RelayCommand(param => this.Exit());
                }
                return m_exitCommand;
            }
        }
        #endregion

        #region Exit
        /// <summary>
        /// 終了します。
        /// </summary>
        public void Exit()
        {
            RaiseRequestClose(new EventArgs());
        }
        #endregion

        #region DescriptionVisibleChangedCommand
        private RelayCommand m_descriptionVisibleChangedCommand;
        /// <summary>
        /// 概要表示／非表示のコマンドを取得します。
        /// </summary>
        public ICommand DescriptionVisibleChangedCommand
        {
            get
            {
                if (m_descriptionVisibleChangedCommand == null)
                {
                    m_descriptionVisibleChangedCommand = new RelayCommand(param => this.DescriptionVisibleChanged());
                }
                return m_descriptionVisibleChangedCommand;
            }
        }
        #endregion

        #region DescriptionVisibleChanged
        /// <summary>
        /// 概要を表示／非表示します。
        /// </summary>
        public void DescriptionVisibleChanged()
        {
            IsDescriptionVisible = !IsDescriptionVisible;
        }
        #endregion

        #region OutputVisibleChangedCommand
        private RelayCommand m_outputVisibleChangedCommand;
        /// <summary>
        /// 出力先の表示／非表示コマンドを取得します。
        /// </summary>
        public ICommand OutputVisibleChangedCommand
        {
            get
            {
                if (m_outputVisibleChangedCommand == null)
                {
                    m_outputVisibleChangedCommand = new RelayCommand(param => this.OutputVisibleChanged());
                }
                return m_outputVisibleChangedCommand;
            }
        }
        #endregion

        #region OutputVisibleChanged
        /// <summary>
        /// 出力先の表示／非表示を変更します。
        /// </summary>
        public void OutputVisibleChanged()
        {
            IsOutputVisible = !IsOutputVisible;
        }
        #endregion

        #region AboutCommand
        private RelayCommand m_aboutCommand;
        /// <summary>
        /// バージョン情報のコマンドを取得します。
        /// </summary>
        public ICommand AboutCommand
        {
            get
            {
                if (m_aboutCommand == null)
                {
                    m_aboutCommand = new RelayCommand(param => this.About());
                }
                return m_aboutCommand;
            }
        }
        #endregion
        
        #region About
        /// <summary>
        /// バージョン情報を表示します。
        /// </summary>
        public void About()
        {
            AbortWindow win = new AbortWindow();
            win.ShowDialog();
        }
        #endregion

        #region RecentFiles
        private ObservableCollection<string> m_recentFiles;
        /// <summary>
        /// 最近使ったファイル一覧を取得します。
        /// </summary>
        public ObservableCollection<string> RecentFiles
        {
            get
            {
                if (m_recentFiles == null)
                {
                    m_recentFiles = new ObservableCollection<string>();
                }
                return m_recentFiles;
            }
        }
        #endregion

        #region Paths
        private ObservableCollection<string> m_paths;
        /// <summary>
        /// 入力フォルダ一覧を取得します。
        /// </summary>
        public ObservableCollection<string> Paths
        {
            get
            {
                if (m_paths == null)
                {
                    m_paths = new ObservableCollection<string>();
                }
                return m_paths;
            }
        }
        #endregion

        #region SearchPatterns
        private ObservableCollection<string> m_searchPatterns;
        /// <summary>
        /// 検索パターン一覧を取得します。
        /// </summary>
        public ObservableCollection<string> SearchPatterns
        {
            get
            {
                if (m_searchPatterns == null)
                {
                    m_searchPatterns = new ObservableCollection<string>();
                }
                return m_searchPatterns;
            }
        }
        #endregion

        #region SearchValues
        private ObservableCollection<string> m_searchValues;
        /// <summary>
        /// 検索文字列一覧を取得します。
        /// </summary>
        public ObservableCollection<string> SearchValues
        {
            get
            {
                if (m_searchValues == null)
                {
                    m_searchValues = new ObservableCollection<string>();
                }
                return m_searchValues;
            }
        }
        #endregion

        #region InputEncodings
        private ObservableCollection<ItemInfo> m_inputEncodings;
        /// <summary>
        /// 入力エンコーディング一覧を取得します。
        /// </summary>
        public ObservableCollection<ItemInfo> InputEncodings
        {
            get
            {
                if (m_inputEncodings == null)
                {
                    m_inputEncodings = new ObservableCollection<ItemInfo>();
                }
                return m_inputEncodings;
            }
        }
        #endregion

        #region OutputPaths
        private ObservableCollection<string> m_outputPaths;
        /// <summary>
        /// 出力フォルダ一覧を取得します。
        /// </summary>
        public ObservableCollection<string> OutputPaths
        {
            get
            {
                if (m_outputPaths == null)
                {
                    m_outputPaths = new ObservableCollection<string>();
                }
                return m_outputPaths;
            }
        }
        #endregion

        #region ConditionsModes
        private ObservableCollection<ItemInfo> m_conditionsModes;
        /// <summary>
        /// 条件一覧を取得します。
        /// </summary>
        public ObservableCollection<ItemInfo> ConditionsModes
        {
            get
            {
                if (m_conditionsModes == null)
                {
                    m_conditionsModes = new ObservableCollection<ItemInfo>();
                }
                return m_conditionsModes;
            }
        }
        #endregion

        #region Constructor
        /// <summary>
        /// 新しいクラスを生成します。
        /// </summary>
        public MainViewModel()
        {
            ConfigLoad();

            LoadResources();
        }
        #endregion

        #region LoadResources
        /// <summary>
        /// リソース読み込み処理を実行します。
        /// </summary>
        public void LoadResources()
        {
            #region InputEncodings
            InputEncodings.Clear();
            InputEncodings.Add(new ItemInfo() { ID = "Auto", Name = Resources.EncodingAuto });
            InputEncodings.Add(new ItemInfo() { ID = "Shift_JIS", Name = Resources.EncodingShiftJIS });
            InputEncodings.Add(new ItemInfo() { ID = "EUC", Name = Resources.EncodingEUC });
            InputEncodings.Add(new ItemInfo() { ID = "UTF8", Name = Resources.EncodingUTF8 });
            InputEncodings.Add(new ItemInfo() { ID = "UTF16LE", Name = Resources.EncodingUTF16LE });
            InputEncodings.Add(new ItemInfo() { ID = "UTF16BE", Name = Resources.EncodingUTF16BE });

            OnPropertyChanged("InputEncodingName");
            #endregion

            #region ConditionsModes
            ConditionsModes.Clear();
            ConditionsModes.Add(new ItemInfo() { ID = "Regex", Name = Resources.ConditionsRegex });
            ConditionsModes.Add(new ItemInfo() { ID = "WildCard", Name = Resources.ConditionsWildCard });

            OnPropertyChanged("ConditionsMode");
            #endregion

            #region ScaleSizes
            ScaleSizes.Clear();
            ScaleSizes.Add(new MenuInfo<double>(Resources.MenuViewSizeBig, BigSizeScale, null));
            ScaleSizes.Add(new MenuInfo<double>(Resources.MenuViewSizeMiddle, MiddleSizeScale, null));
            ScaleSizes.Add(new MenuInfo<double>(Resources.MenuViewSizeSmall, SmallSizeScale, null));
            foreach (MenuInfo<double> size in ScaleSizes)
            {
                if (size.Value == ScaleSize)
                {
                    size.IsChecked = true;
                }
                else
                {
                    size.IsChecked = false;
                }
            }
            #endregion
        }
        #endregion

        #region IsDescriptionVisible
        private bool m_isDescriptionVisible = false;
        /// <summary>
        /// 概要の表示／非表示を取得または設定します。
        /// </summary>
        public bool IsDescriptionVisible
        {
            get
            {
                return m_isDescriptionVisible;
            }
            set
            {
                if (m_isDescriptionVisible == value)
                {
                    return;
                }
                m_isDescriptionVisible = value;
                OnPropertyChanged("IsDescriptionVisible");
            }
        }
        #endregion

        #region IsOutputVisible
        private bool m_isOutputVisible = false;
        /// <summary>
        /// 出力先の表示／非表示を取得または設定します。
        /// </summary>
        public bool IsOutputVisible
        {
            get
            {
                return m_isOutputVisible;
            }
            set
            {
                if (m_isOutputVisible == value)
                {
                    return;
                }
                m_isOutputVisible = value;
                if (!IsOutputVisible)
                {
                    IsOutputPath = false;
                }
                OnPropertyChanged("IsOutputVisible");
            }
        }
        #endregion

        #region RequestClose
        /// <summary>
        /// クローズ要求イベント
        /// </summary>
        public event EventHandler<EventArgs> RequestClose;
        /// <summary>
        /// 指定したイベントデータで、クローズ要求イベントを実行します。
        /// </summary>
        /// <param name="e">イベントデータ</param>
        internal void RaiseRequestClose(EventArgs e)
        {
            ConfigSave();
            if (RequestClose != null)
            {
                RequestClose(this, e);
            }
        }
        #endregion
    }
}
